/*
 * © 2024 huayunliufeng保留所有权利, 依据MIT许可证发布。
 * 请勿更改或删除版权声明或此文件头。
 * 此代码是免费软件, 您可以重新分发和/或修改它。
 * 开源是希望它有用, 但不对代码做任何保证。
 * 如有疑问请联系: huayunliufeng@163.com
 */

package io.github.huayunliufeng.common.utils;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 和集合、数组相关的常用方法。
 *
 * @author zhongq
 * @datetime 2024/3/22 17:16
 */
final public class HylfCollectionUtil {

    private static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * 集合是否为空。
     *
     * @param collection collection
     * @param <T>        T
     * @return true or false
     */
    public static <T> boolean isEmpty(final Collection<T> collection) {
        return collection == null || collection.isEmpty();
    }

    public static <K, V> boolean isEmpty(final Map<K, V> map) {
        return map == null || map.isEmpty();
    }


    public static boolean isEmpty(final char[] chars) {
        return chars == null || chars.length == 0;
    }

    public static boolean isEmpty(final int[] ints) {
        return ints == null || ints.length == 0;
    }

    public static boolean isEmpty(final byte[] bytes) {
        return bytes == null || bytes.length == 0;
    }

    public static boolean isEmpty(final short[] shorts) {
        return shorts == null || shorts.length == 0;
    }

    public static boolean isEmpty(final long[] longs) {
        return longs == null || longs.length == 0;
    }

    public static boolean isEmpty(final double[] doubles) {
        return doubles == null || doubles.length == 0;
    }

    public static boolean isEmpty(final boolean[] booleans) {
        return booleans == null || booleans.length == 0;
    }

    public static boolean isEmpty(final float[] floats) {
        return floats == null || floats.length == 0;
    }

    public static boolean isEmpty(final Object[] objects) {
        return objects == null || objects.length == 0;
    }

    public static <T> boolean isNotEmpty(final Collection<T> collection) {
        return collection != null && !collection.isEmpty();
    }

    public static <K, V> boolean isNotEmpty(final Map<K, V> map) {
        return map != null && !map.isEmpty();
    }

    public static boolean isNotEmpty(final char[] chars) {
        return chars != null && chars.length != 0;
    }

    public static boolean isNotEmpty(final int[] ints) {
        return ints != null && ints.length != 0;
    }

    public static boolean isNotEmpty(final byte[] bytes) {
        return bytes != null && bytes.length != 0;
    }

    public static boolean isNotEmpty(final short[] shorts) {
        return shorts != null && shorts.length != 0;
    }

    public static boolean isNotEmpty(final long[] longs) {
        return longs != null && longs.length != 0;
    }

    public static boolean isNotEmpty(final double[] doubles) {
        return doubles != null && doubles.length != 0;
    }

    public static boolean isNotEmpty(final boolean[] booleans) {
        return booleans != null && booleans.length != 0;
    }

    public static boolean isNotEmpty(final float[] floats) {
        return floats != null && floats.length != 0;
    }

    public static boolean isNotEmpty(final Object[] objects) {
        return objects != null && objects.length != 0;
    }

    /**
     * Object[]转换为boolean[], 前提是原数组确实是boolean类型
     *
     * @param objects     objects
     * @param valueFoNull 原数组该元素为空时, 输出的数组默认值是什么
     * @return boolean[]
     */
    public static boolean[] objectArrayToBooleanArray(final Object[] objects, boolean valueFoNull) {
        if (isEmpty(objects)) {
            return new boolean[0];
        }
        int n = objects.length;
        Boolean[] booleans = new Boolean[n];
        for (int i = 0; i < n; i++) {
            booleans[i] = (Boolean) objects[i];
        }
        return ArrayUtils.toPrimitive(booleans, valueFoNull);
    }

    /**
     * Object[]转换为char[], 前提是原数组确实是char类型
     *
     * @param objects     objects
     * @param valueFoNull 原数组该元素为空时, 输出的数组默认值是什么
     * @return char[]
     */
    public static char[] objectArrayToCharArray(final Object[] objects, char valueFoNull) {
        if (isEmpty(objects)) {
            return new char[0];
        }
        int n = objects.length;
        Character[] characters = new Character[n];
        for (int i = 0; i < n; i++) {
            characters[i] = (Character) objects[i];
        }
        return ArrayUtils.toPrimitive(characters, valueFoNull);
    }

    /**
     * Object[]转换为byte[], 前提是原数组确实是byte类型
     *
     * @param objects     objects
     * @param valueFoNull 原数组该元素为空时, 输出的数组默认值是什么
     * @return byte[]
     */
    public static byte[] objectArrayToByteArray(final Object[] objects, byte valueFoNull) {
        if (isEmpty(objects)) {
            return new byte[0];
        }
        int n = objects.length;
        Byte[] bytes = new Byte[n];
        for (int i = 0; i < n; i++) {
            bytes[i] = (Byte) objects[i];
        }
        return ArrayUtils.toPrimitive(bytes, valueFoNull);
    }

    /**
     * Object[]转换为short[], 前提是原数组确实是short类型
     *
     * @param objects     objects
     * @param valueFoNull 原数组该元素为空时, 输出的数组默认值是什么
     * @return short[]
     */
    public static short[] objectArrayToShortArray(final Object[] objects, short valueFoNull) {
        if (isEmpty(objects)) {
            return new short[0];
        }
        int n = objects.length;
        Short[] shorts = new Short[n];
        for (int i = 0; i < n; i++) {
            shorts[i] = (Short) objects[i];
        }
        return ArrayUtils.toPrimitive(shorts, valueFoNull);
    }

    /**
     * Object[]转换为int[], 前提是原数组确实是int类型
     *
     * @param objects     objects
     * @param valueFoNull 原数组该元素为空时, 输出的数组默认值是什么
     * @return int[]
     */
    public static int[] objectArrayToIntArray(final Object[] objects, int valueFoNull) {
        if (isEmpty(objects)) {
            return new int[0];
        }
        int n = objects.length;
        Integer[] integers = new Integer[n];
        for (int i = 0; i < n; i++) {
            integers[i] = (Integer) objects[i];
        }
        return ArrayUtils.toPrimitive(integers, valueFoNull);
    }

    /**
     * Object[]转换为long[], 前提是原数组确实是long类型
     *
     * @param objects     objects
     * @param valueFoNull 原数组该元素为空时, 输出的数组默认值是什么
     * @return long[]
     */
    public static long[] objectArrayToLongArray(final Object[] objects, long valueFoNull) {
        if (isEmpty(objects)) {
            return new long[0];
        }
        int n = objects.length;
        Long[] longs = new Long[n];
        for (int i = 0; i < n; i++) {
            longs[i] = (Long) objects[i];
        }
        return ArrayUtils.toPrimitive(longs, valueFoNull);
    }

    /**
     * Object[]转换为double[], 前提是原数组确实是double类型
     *
     * @param objects     objects
     * @param valueFoNull 原数组该元素为空时, 输出的数组默认值是什么
     * @return double[]
     */
    public static double[] objectArrayToDoubleArray(final Object[] objects, double valueFoNull) {
        if (isEmpty(objects)) {
            return new double[0];
        }
        int n = objects.length;
        Double[] doubles = new Double[n];
        for (int i = 0; i < n; i++) {
            doubles[i] = (Double) objects[i];
        }
        return ArrayUtils.toPrimitive(doubles, valueFoNull);
    }

    /**
     * Object[]转换为指定对象类型, 如果为空或null则返回指定类型的空数组
     *
     * @param objects     objects
     * @param valueFoNull 原数组该元素为空时, 输出的数组默认值是什么
     * @return T[]
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] objectArrayToArray(final Object[] objects, final T valueFoNull, final Class<T> type) {
        if (isEmpty(objects)) {
            return (T[]) Array.newInstance(type, 0);
        }
        int n = objects.length;
        T[] ts = (T[]) Array.newInstance(type, n);
        for (int i = 0; i < n; i++) {
            ts[i] = objects[i] == null ? valueFoNull : (T) objects[i];
        }
        return ts;
    }

    /**
     * Object[]转换为float[], 前提是原数组确实是float类型
     *
     * @param objects     objects
     * @param valueFoNull 原数组该元素为空时, 输出的数组默认值是什么
     * @return float[]
     */
    public static float[] objectArrayToFloatArray(final Object[] objects, float valueFoNull) {
        if (isEmpty(objects)) {
            return new float[0];
        }
        int n = objects.length;
        Float[] floats = new Float[n];
        for (int i = 0; i < n; i++) {
            floats[i] = (Float) objects[i];
        }
        return ArrayUtils.toPrimitive(floats, valueFoNull);
    }


    /**
     * 将对象数组的所有元素添加到集合中, 数组不能过大
     *
     * @param collection collection
     * @param eleArray   eleArray
     */
    public static <T> void appendAll(final Collection<T> collection, final T[]... eleArray) {
        if (collection == null || isEmpty(eleArray)) {
            return;
        }
        if (eleArray.length >= Integer.MAX_VALUE * DEFAULT_LOAD_FACTOR) {
            throw new RuntimeException("数组过大。");
        }
        for (T[] eles : eleArray) {
            collection.addAll(Arrays.asList(eles));
        }
    }

    /**
     * 将char数组的所有元素添加到指定集合中
     *
     * @param collection collection
     * @param charArray  charArray
     */
    public static void appendAll(final Collection<Character> collection, final char[]... charArray) {
        if (isEmpty(charArray)) {
            return;
        }
        int n = charArray.length;
        Character[][] eles = new Character[n][];
        for (int i = 0; i < n; i++) {
            int m = charArray[i].length;
            eles[i] = new Character[m];
            for (int j = 0; j < m; j++) {
                eles[i][j] = charArray[i][j];
            }
        }
        appendAll(collection, eles);
    }

    /**
     * 将int数组的所有元素添加到指定集合中
     *
     * @param collection collection
     * @param intArray   intArray
     */
    public static void appendAll(final Collection<Integer> collection, final int[]... intArray) {
        if (isEmpty(intArray)) {
            return;
        }
        int n = intArray.length;

        Integer[][] eles = new Integer[n][];
        for (int i = 0; i < n; i++) {
            int m = intArray[i].length;
            eles[i] = new Integer[m];
            for (int j = 0; j < m; j++) {
                eles[i][j] = intArray[i][j];
            }
        }
        appendAll(collection, eles);
    }

    /**
     * 将short数组的所有元素添加到指定集合中
     *
     * @param collection collection
     * @param shortArray shortArray
     */
    public static void appendAll(final Collection<Short> collection, final short[]... shortArray) {
        if (isEmpty(shortArray)) {
            return;
        }
        int n = shortArray.length;
        Short[][] eles = new Short[n][];
        for (int i = 0; i < n; i++) {
            int m = shortArray[i].length;
            eles[i] = new Short[m];
            for (int j = 0; j < m; j++) {
                eles[i][j] = shortArray[i][j];
            }
        }
        appendAll(collection, eles);
    }

    /**
     * 将byte数组的所有元素添加到指定集合中
     *
     * @param collection collection
     * @param byteArray  byteArray
     */
    public static void appendAll(final Collection<Byte> collection, final byte[]... byteArray) {
        if (isEmpty(byteArray)) {
            return;
        }
        int n = byteArray.length;
        Byte[][] eles = new Byte[n][];
        for (int i = 0; i < n; i++) {
            int m = byteArray[i].length;
            eles[i] = new Byte[m];
            for (int j = 0; j < m; j++) {
                eles[i][j] = eles[i][j];
            }
        }
        appendAll(collection, eles);
    }

    /**
     * 将long数组的所有元素添加到指定集合中
     *
     * @param collection collection
     * @param longArray  longArray
     */
    public static void appendAll(final Collection<Long> collection, final long[]... longArray) {
        if (isEmpty(longArray)) {
            return;
        }
        int n = longArray.length;
        Long[][] eles = new Long[n][];
        for (int i = 0; i < n; i++) {
            int m = longArray[i].length;
            eles[i] = new Long[m];
            for (int j = 0; j < m; j++) {
                eles[i][j] = eles[i][j];
            }
        }
        appendAll(collection, eles);
    }

    /**
     * 将double数组的所有元素添加到指定集合中
     *
     * @param collection  collection
     * @param doubleArray doubleArray
     */
    public static void appendAll(final Collection<Double> collection, final double[]... doubleArray) {
        if (isEmpty(doubleArray)) {
            return;
        }
        int n = doubleArray.length;
        Double[][] eles = new Double[n][];
        for (int i = 0; i < n; i++) {
            int m = doubleArray[i].length;
            eles[i] = new Double[m];
            for (int j = 0; j < m; j++) {
                eles[i][j] = eles[i][j];
            }
        }
        appendAll(collection, eles);
    }

    /**
     * 将float数组的所有元素添加到指定集合中
     *
     * @param collection collection
     * @param floatArray floatArray
     */
    public static void appendAll(final Collection<Float> collection, final float[]... floatArray) {
        if (isEmpty(floatArray)) {
            return;
        }
        int n = floatArray.length;
        Float[][] eles = new Float[n][];
        for (int i = 0; i < n; i++) {
            int m = floatArray[i].length;
            eles[i] = new Float[m];
            for (int j = 0; j < m; j++) {
                eles[i][j] = eles[i][j];
            }
        }
        appendAll(collection, eles);
    }

    /**
     * 将boolean数组的所有元素添加到指定集合中
     *
     * @param collection   collection
     * @param booleanArray booleanArray
     */
    public static void appendAll(final Collection<Boolean> collection, final boolean[]... booleanArray) {
        if (isEmpty(booleanArray)) {
            return;
        }
        int n = booleanArray.length;
        Boolean[][] eles = new Boolean[n][];
        for (int i = 0; i < n; i++) {
            int m = booleanArray[i].length;
            eles[i] = new Boolean[m];
            for (int j = 0; j < m; j++) {
                eles[i][j] = eles[i][j];
            }
        }
        appendAll(collection, eles);
    }


    /**
     * 将集合转为指定对象类型的数组, 如果集合为空或null, 返回空数组
     *
     * @param collection collection
     * @param type       数组类型
     * @return 指定对象类型的数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] collectionToArray(final Collection<T> collection, final Class<T> type) {
        if (isEmpty(collection)) {
            return (T[]) Array.newInstance(type, 0);
        }
        int size = collection.size();
        T[] ts = (T[]) Array.newInstance(type, size);
        int i = 0;
        for (T t : collection) {
            ts[i++] = t;
        }
        return ts;
    }

    /**
     * 将集合转为char数组, 如果集合为空或null, 返回空char数组
     *
     * @param collection collection
     * @return char[]
     */
    public static char[] collectionToCharArray(final Collection<Character> collection) {
        if (isEmpty(collection)) {
            return new char[0];
        }
        int size = collection.size();
        char[] chars = new char[size];
        int i = 0;
        for (Character ele : collection) {
            chars[i++] = ele;
        }
        return chars;
    }

    /**
     * 将集合转为byte数组, 如果集合为空或null, 返回空byte数组
     *
     * @param collection collection
     * @return byte[]
     */
    public static byte[] collectionToByteArray(final Collection<Byte> collection) {
        if (isEmpty(collection)) {
            return new byte[0];
        }
        int size = collection.size();
        byte[] bytes = new byte[size];
        int i = 0;
        for (Byte ele : collection) {
            bytes[i++] = ele;
        }
        return bytes;
    }

    /**
     * 将集合转为short数组, 如果集合为空或null, 返回空short数组
     *
     * @param collection collection
     * @return short[]
     */
    public static short[] collectionToShortArray(final Collection<Short> collection) {
        if (isEmpty(collection)) {
            return new short[0];
        }
        int size = collection.size();
        short[] shorts = new short[size];
        int i = 0;
        for (Short ele : collection) {
            shorts[i++] = ele;
        }
        return shorts;
    }

    /**
     * 将集合转为int数组, 如果集合为空或null, 返回空int数组
     *
     * @param collection collection
     * @return int[]
     */
    public static int[] collectionToIntArray(final Collection<Integer> collection) {
        if (isEmpty(collection)) {
            return new int[0];
        }
        int size = collection.size();
        int[] ints = new int[size];
        int i = 0;
        for (Integer ele : collection) {
            ints[i++] = ele;
        }
        return ints;
    }

    /**
     * 将集合转为long数组, 如果集合为空或null, 返回空long数组
     *
     * @param collection collection
     * @return long[]
     */
    public static long[] collectionToLongArray(final Collection<Long> collection) {
        if (isEmpty(collection)) {
            return new long[0];
        }
        int size = collection.size();
        long[] longs = new long[size];
        int i = 0;
        for (Long ele : collection) {
            longs[i++] = ele;
        }
        return longs;
    }

    /**
     * 将集合转为double数组, 如果集合为空或null, 返回空double数组
     *
     * @param collection collection
     * @return double[]
     */
    public static double[] collectionToDoubleArray(final Collection<Double> collection) {
        if (isEmpty(collection)) {
            return new double[0];
        }
        int size = collection.size();
        double[] doubles = new double[size];
        int i = 0;
        for (Double ele : collection) {
            doubles[i++] = ele;
        }
        return doubles;
    }

    /**
     * 将集合转为float数组, 如果集合为空或null, 返回空float数组
     *
     * @param collection collection
     * @return float[]
     */
    public static float[] collectionToFloatArray(final Collection<Float> collection) {
        if (isEmpty(collection)) {
            return new float[0];
        }
        int size = collection.size();
        float[] floats = new float[size];
        int i = 0;
        for (Float ele : collection) {
            floats[i++] = ele;
        }
        return floats;
    }

    /**
     * 将集合转为boolean数组, 如果集合为空或null, 返回空boolean数组
     *
     * @param collection collection
     * @return boolean[]
     */
    public static boolean[] collectionToBooleanArray(final Collection<Boolean> collection) {
        if (isEmpty(collection)) {
            return new boolean[0];
        }
        int size = collection.size();
        boolean[] booleans = new boolean[size];
        int i = 0;
        for (Boolean ele : collection) {
            booleans[i++] = ele;
        }
        return booleans;
    }

    /**
     * 合并指定类型的数组, 如果为空, 返回空数组
     *
     * @param type   数组元素类型
     * @param tArray 可变参数的对象数组
     * @return 按照传入顺序合并的数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] mergeArray(final Class<T> type, final T[]... tArray) {
        if (isEmpty(tArray)) {
            return (T[]) Array.newInstance(type, 0);
        }
        List<T> result = new ArrayList<>();
        appendAll(result, tArray);
        return collectionToArray(result, type);
    }


    /**
     * 合并char类型的数组, 如果为空, 返回空数组
     *
     * @param chars 可变参数的char数组
     * @return 按照传入顺序合并的数组
     */
    public static char[] mergeCharArray(final char[]... chars) {
        if (isEmpty(chars)) {
            return new char[0];
        }
        List<Character> result = new ArrayList<>();
        appendAll(result, chars);
        return collectionToCharArray(result);
    }

    /**
     * 合并byte类型的数组, 如果为空, 返回空数组
     *
     * @param bytes 可变参数的byte数组
     * @return 按照传入顺序合并的数组
     */
    public static byte[] mergeByteArray(final byte[]... bytes) {
        if (isEmpty(bytes)) {
            return new byte[0];
        }
        List<Byte> result = new ArrayList<>();
        appendAll(result, bytes);
        return collectionToByteArray(result);
    }

    /**
     * 合并short类型的数组, 如果为空, 返回空数组
     *
     * @param shorts 可变参数的short数组
     * @return 按照传入顺序合并的数组
     */
    public static short[] mergeShortArray(final short[]... shorts) {
        if (isEmpty(shorts)) {
            return new short[0];
        }
        List<Short> result = new ArrayList<>();
        appendAll(result, shorts);
        return collectionToShortArray(result);
    }

    /**
     * 合并int类型的数组, 如果为空, 返回空数组
     *
     * @param ints 可变参数的int数组
     * @return 按照传入顺序合并的数组
     */
    public static int[] mergeIntArray(final int[]... ints) {
        if (isEmpty(ints)) {
            return new int[0];
        }
        List<Integer> result = new ArrayList<>();
        appendAll(result, ints);
        return collectionToIntArray(result);
    }

    /**
     * 合并long类型的数组, 如果为空, 返回空数组
     *
     * @param longs 可变参数的long数组
     * @return 按照传入顺序合并的数组
     */
    public static long[] mergeLongArray(final long[]... longs) {
        if (isEmpty(longs)) {
            return new long[0];
        }
        List<Long> result = new ArrayList<>();
        appendAll(result, longs);
        return collectionToLongArray(result);
    }

    /**
     * 合并double类型的数组, 如果为空, 返回空数组
     *
     * @param doubles 可变参数的double数组
     * @return 按照传入顺序合并的数组
     */
    public static double[] mergeDoubleArray(final double[]... doubles) {
        if (isEmpty(doubles)) {
            return new double[0];
        }
        List<Double> result = new ArrayList<>();
        appendAll(result, doubles);
        return collectionToDoubleArray(result);
    }

    /**
     * 合并float类型的数组, 如果为空, 返回空数组
     *
     * @param floats 可变参数的float数组
     * @return 按照传入顺序合并的数组
     */
    public static float[] mergeFloatArray(final float[]... floats) {
        if (isEmpty(floats)) {
            return new float[0];
        }
        List<Float> result = new ArrayList<>();
        appendAll(result, floats);
        return collectionToFloatArray(result);
    }

    /**
     * 合并boolean类型的数组, 如果为空, 返回空数组
     *
     * @param booleans 可变参数的boolean数组
     * @return 按照传入顺序合并的数组
     */
    public static boolean[] mergeBooleanArray(final boolean[]... booleans) {
        if (isEmpty(booleans)) {
            return new boolean[0];
        }
        List<Boolean> result = new ArrayList<>();
        appendAll(result, booleans);
        return collectionToBooleanArray(result);
    }

    /**
     * 过滤集合, 并返回过滤后的数组
     *
     * @param srcList    数据源
     * @param type       集合元素类型
     * @param ignoreEles 需要过滤的元素
     * @return 过滤后的数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] filterListToArray(final Collection<T> srcList, final Class<T> type, final String... ignoreEles) {
        if (isEmpty(srcList)) {
            return (T[]) Array.newInstance(type, 0);
        }
        List<T> result = srcList.stream().filter(s -> {
            if (isEmpty(ignoreEles)) {
                return true;
            }
            for (String ignoreEle : ignoreEles) {
                if (ignoreEle.equals(s)) {
                    return false;
                }
            }
            return true;
        }).collect(Collectors.toList());
        T[] ts = (T[]) Array.newInstance(type, result.size());
        for (int i = 0; i < ts.length; i++) {
            ts[i] = result.get(i);
        }
        return ts;
    }

    /**
     * 判断字符在不在指定字符串中
     *
     * @param ch  目标字符
     * @param str 目标字符串
     * @return true or false
     */
    public static boolean charInStr(char ch, String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        int len = str.length();
        for (int i = 0; i < len; i++) {
            char c = str.charAt(i);
            if (c == ch) {
                return true;
            }
        }
        return false;
    }
}
